﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024-2025 LiLong                                              **
**  This file is part of OpenVisaApplication.                                   **
**                                                                              **
**  OpenVisaApplication is free software: you can redistribute it and/or modify **
**  it under the terms of the GNU General Public License as published by        **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  OpenVisaApplication is distributed in the hope that it will be useful,      **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU General Public License for more details.                                **
**                                                                              **
**  You should have received a copy of the GNU General Public License           **
**  along with OpenVisaApplication. If not, see <https://www.gnu.org/licenses/>.**
**********************************************************************************/
#include "DeviceListView.h"
#include "Attribute/AttributeDialog.h"
#include "DeviceListModel.h"
#include "NetworkDevice/AddNetworkDeviceDialog.h"

#include <AppCore/Device.h>
#include <AppCore/DeviceGroup.h>
#include <QCustomUi/QCtmMessageBox.h>

#include <QApplication>
#include <QClipboard>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QItemSelectionModel>
#include <QMenu>
#include <QTreeView>

struct DeviceListView::Impl
{
    QHBoxLayout* layout { nullptr };
    QTreeView* treeView { nullptr };
    DeviceListModel* model { nullptr };
    QAction* copyAddressAction { nullptr };
};

DeviceListView::DeviceListView(QWidget* parent) : QWidget(parent), m_impl(std::make_unique<Impl>())
{
    m_impl->layout = new QHBoxLayout(this);
    m_impl->layout->setContentsMargins(0, 0, 0, 0);
    m_impl->treeView = new QTreeView(this);
    m_impl->treeView->header()->hide();
    m_impl->layout->addWidget(m_impl->treeView);
    m_impl->treeView->setModel(m_impl->model = new DeviceListModel(this));
    m_impl->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
    m_impl->treeView->expandAll();
    m_impl->copyAddressAction = addAction(
        QIcon(":/OpenVisaApplication/Resources/Copy.svg"), u8"复制地址", QKeySequence::Copy, this, &DeviceListView::onCopyAddressAction);
    m_impl->copyAddressAction->setShortcutContext(Qt::WidgetWithChildrenShortcut);
    connect(m_impl->treeView, &QTreeView::customContextMenuRequested, this, &DeviceListView::onCustomContextMenuRequested);
    connect(m_impl->treeView, &QTreeView::doubleClicked, this, &DeviceListView::onDoubleClicked);
    connect(m_impl->model, &DeviceListModel::deviceRemoved, this, &DeviceListView::closeDevice);
}

DeviceListView::~DeviceListView()
{
}

void DeviceListView::onDoubleClicked(const QModelIndex& index)
{
    auto item = index.isValid() ? m_impl->model->deviceItem(index) : nullptr;
    if (!item)
        return;
    emit openDevice(item);
}

void DeviceListView::onOnlyShowViewAction(const QModelIndex& index)
{
    auto item = index.isValid() ? m_impl->model->deviceItem(index) : nullptr;
    if (!item)
        return;
    emit onlyShowView(item);
}

void DeviceListView::onCustomContextMenuRequested(const QPoint& pos)
{
    auto index = m_impl->treeView->indexAt(pos);
    if (!index.isValid())
        return;
    auto item = m_impl->model->deviceItem(index);
    QMenu menu(this);

    if (auto group = dynamic_pointer_cast<AppCore::DeviceGroup>(item); group) // 分组菜单
    {
        if (auto net = dynamic_pointer_cast<AppCore::NetworkGroup>(group); net)
        {
            menu.addAction(u8"添加网络设备", this, &DeviceListView::onAddNetworkDevice);
        }
        else if (auto sp = dynamic_pointer_cast<AppCore::SerialPortGroup>(item); sp)
        {
            menu.addAction(u8"刷新", this, &DeviceListView::onUpdateSerialPortDevices);
        }
        else if (auto usb = dynamic_pointer_cast<AppCore::UsbTmcGroup>(item); usb)
        {
            menu.addAction(u8"刷新", this, &DeviceListView::onUpdateUSBs);
        }
    }
    else if (auto dev = dynamic_pointer_cast<AppCore::Device>(item); dev) // 设备菜单
    {
        menu.addAction(u8"打开", std::bind_front(&DeviceListView::onDoubleClicked, this, index));
        menu.addAction(u8"仅打开视图", std::bind_front(&DeviceListView::onOnlyShowViewAction, this, index));
        menu.addAction(m_impl->copyAddressAction);
        if (auto net = dynamic_pointer_cast<AppCore::NetworkDevice>(dev); net)
        {
            menu.addAction(QIcon(":/OpenVisaApplication/Resources/Delete.svg"),
                           u8"删除",
                           std::bind_front(&DeviceListView::onRemoveNetworkDevice, this, index));
        }
        menu.addSeparator();
        menu.addAction(u8"设备属性", std::bind_front(&DeviceListView::onDeviceAttributeAction, this, index));
    }
    else
        return;
    menu.exec(QCursor::pos());
}

void DeviceListView::onAddNetworkDevice()
{
    AddNetworkDeviceDialog dlg(this);
    if (dlg.exec() != AddNetworkDeviceDialog::Accepted)
        return;
    m_impl->model->addNetworkDevice(dlg.address());
}

void DeviceListView::onRemoveNetworkDevice(const QModelIndex& index)
{
    if (!index.isValid())
        return;
    if (QCtmMessageBox::question(this, u8"警告", u8"确认删除？") != QCtmMessageBox::Yes)
        return;
    auto item = m_impl->model->deviceItem(index);
    if (!item)
        return;
    m_impl->model->removeNetworkDevice(index);
}

void DeviceListView::onUpdateSerialPortDevices()
{
    m_impl->model->updateSerialPort();
    m_impl->treeView->expandAll();
}

void DeviceListView::onUpdateUSBs()
{
    m_impl->model->updateUsbTmc();
    m_impl->treeView->expandAll();
}

void DeviceListView::onDeviceAttributeAction(const QModelIndex& index)
{
    if (!index.isValid())
        return;
    auto dev = dynamic_pointer_cast<AppCore::Device>(m_impl->model->deviceItem(index));
    if (!dev)
        return;
    bool isSerialPort = static_cast<bool>(dynamic_pointer_cast<AppCore::SerialPortDevice>(dev));
    AttributeDialog dlg(dev->object(), isSerialPort, this);
    dlg.exec();
}

void DeviceListView::onCopyAddressAction()
{
    auto index = m_impl->treeView->currentIndex();
    if (!index.isValid())
        return;
    auto dev = dynamic_pointer_cast<AppCore::Device>(m_impl->model->deviceItem(index));
    if (!dev)
        return;
    qApp->clipboard()->setText(dev->address());
}
